package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.course.CatalogueClient;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CataSimpleInfoDTO;
import com.tianji.api.dto.course.CourseSimpleInfoDTO;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.domain.query.PageQuery;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.AssertUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningPlanDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.domain.vo.LearningLessonVO;
import com.tianji.learning.domain.vo.LearningPlanPageVO;
import com.tianji.learning.domain.vo.LearningPlanVO;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.PlanStatus;
import com.tianji.learning.mapper.LearningLessonMapper;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.el.lang.FunctionMapperImpl;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 学生课程表 服务实现类
 * </p>
 *
 * @author hc
 * @since 2024-08-20
 */

@Slf4j
@Service
public class LearningLessonServiceImpl extends ServiceImpl<LearningLessonMapper, LearningLesson> implements ILearningLessonService {

    @Autowired
    private CourseClient courseClient;

    @Autowired
    private CatalogueClient catalogueClient;

    @Autowired
    private LearningRecordMapper recordMapper;

    /**
     * 将购买的课程加入到我的课程
     *
     * @param userId    购买人id
     * @param courseIds 购买的课程id
     */
    @Override
    public void addMyLessonsByCourseIds(Long userId, List<Long> courseIds) {
        //1、根据所购买的课程ids去获取简单的课程信息
        List<CourseSimpleInfoDTO> courseInfos = courseClient.getSimpleInfoList(courseIds);

        //判断是否为空
        if (ObjectUtil.isEmpty(courseInfos)) {
            return;
        }

        //2、封装learningLesson对象
        List<LearningLesson> learningLessons = new ArrayList<>(courseInfos.size());
        for (CourseSimpleInfoDTO courseInfo : courseInfos) {
            LearningLesson learningLesson = new LearningLesson();
            learningLesson.setCourseId(courseInfo.getId());
            learningLesson.setUserId(userId);

            //2.1、封装过期时间
            //2.1.1、判断过期时间是否有效
            Integer expire = courseInfo.getValidDuration();
            if (ObjectUtil.isEmpty(expire) || expire < 0) {
                continue;
            }

            //2.1.2、开始封装时间
            if (expire < 9999) {
                learningLesson.setExpireTime(LocalDateTime.now().plusMonths(expire));
            }
            learningLessons.add(learningLesson);
        }

        saveBatch(learningLessons);
    }

    /**
     * 查询已购买的课程列表
     *
     * @param pageQuery 查询条件
     * @return 已购买的课程列表
     */
    @Override
    public PageDTO<LearningLessonVO> pageQueryMyLessons(PageQuery pageQuery) {
        //1、获取当前用户的id
        Long userId = UserContext.getUser();

        if (ObjectUtil.isEmpty(userId)) {
            log.error("没有获取到用户id");
            return PageDTO.empty(0L, 0L);
        }
        //2、查询当前用户所购买的课程
        Page<LearningLesson> learningLessonPage = new Page<>(pageQuery.getPageNo(), pageQuery.getPageSize());
        //2.1、判断有没有给排序字段
        if (ObjectUtil.isEmpty(pageQuery.getSortBy())) {
            //没有则默认按学习时间降序
            learningLessonPage.addOrder(new OrderItem("latest_learn_time", false));
        } else {
            //有则按照排序字段排序
            learningLessonPage.addOrder(new OrderItem(pageQuery.getSortBy(), pageQuery.getIsAsc()));
        }

        Page<LearningLesson> page = lambdaQuery().eq(LearningLesson::getUserId, userId).page(learningLessonPage);

        List<LearningLesson> lessons = page.getRecords();

        if (ObjectUtil.isEmpty(lessons)) {
            log.info("没有找到相关课程");
            return PageDTO.empty(page);
        }

        //3、根据当前用户所购买的课程中的课程id来获得一些课程的基本信息
        Set<Long> courseIds = lessons.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());

        //3.1、查询用户课程的基本信息
        List<CourseSimpleInfoDTO> courseInfos = courseClient.getSimpleInfoList(courseIds);

        //3.2、将课程信息集合转化成map
        Map<Long, CourseSimpleInfoDTO> courseInfoMap = courseInfos.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, s -> s));

        //4、开始封装返回结果数据
        List<LearningLessonVO> learningLessonVOS = new ArrayList<>(lessons.size());
        for (LearningLesson lesson : lessons) {
            LearningLessonVO learningLessonVO = BeanUtil.toBean(lesson, LearningLessonVO.class);
            learningLessonVO.setCourseName(courseInfoMap.get(learningLessonVO.getCourseId()).getName());
            learningLessonVO.setCourseCoverUrl(courseInfoMap.get(learningLessonVO.getCourseId()).getCoverUrl());
            learningLessonVO.setSections(courseInfoMap.get(learningLessonVO.getCourseId()).getSectionNum());
            learningLessonVOS.add(learningLessonVO);
        }

        return PageDTO.of(learningLessonPage, learningLessonVOS);
    }

    /**
     * 查询当前正在学习的课程
     *
     * @return 课程
     */
    @Override
    public LearningLessonVO queryMyNowStudy() {
        //1、获取当前用户id
        Long userId = UserContext.getUser();

        //2、查询当前用户所购买的课程
        Page<LearningLesson> learningLessonPage = new Page<>(1, 1);
        //2.1、降序排序课程
        learningLessonPage.addOrder(new OrderItem("latest_learn_time", false));
        Page<LearningLesson> page = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .page(learningLessonPage);
        //2.2、获取到最新的哪个课程
        LearningLesson lesson = page.getRecords().get(0);

        if (lesson == null) {
            return null;
        }

        LearningLessonVO learningLessonVO = BeanUtil.toBean(lesson, LearningLessonVO.class);
        //3、查询当前所学小节名称
        ArrayList<Long> longs = new ArrayList<>();
        longs.add(lesson.getLatestSectionId());
        List<CataSimpleInfoDTO> cataSimpleInfos = catalogueClient.batchQueryCatalogue(longs);

        //4、查询用户课程的基本信息来获取课程名称
        ArrayList<Long> id = new ArrayList<>(1);
        id.add(lesson.getCourseId());
        List<CourseSimpleInfoDTO> courseInfo = courseClient.getSimpleInfoList(id);

        //5、开始封装返回结果
        learningLessonVO.setCourseAmount(Math.toIntExact(page.getTotal()));
        learningLessonVO.setLatestSectionName(cataSimpleInfos.get(0).getName());
        learningLessonVO.setLatestSectionIndex(Long.valueOf(cataSimpleInfos.get(0).getCIndex()));
        learningLessonVO.setCourseName(courseInfo.get(0).getName());
        learningLessonVO.setSections(courseInfo.get(0).getSectionNum());
        learningLessonVO.setCourseCoverUrl(courseInfo.get(0).getCoverUrl());


        return learningLessonVO;
    }

    /**
     * 查询用户课表中指定课程状态
     *
     * @param courseId 课程id
     * @return 课程vo
     */
    @Override
    public LearningLessonVO queryLessonStatus(Long courseId) {
        //1、根据课程id查到课程
        Long userId = UserContext.getUser();
        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningLesson::getCourseId, courseId).eq(LearningLesson::getUserId, userId);
        LearningLesson learningLesson = this.getOne(queryWrapper);

        //2、转成vo
        LearningLessonVO learningLessonVO = BeanUtil.toBean(learningLesson, LearningLessonVO.class);
        return learningLessonVO;
    }

    /**
     * 校验当前用户是否可以学习当前课程
     *
     * @param courseId 课程id
     * @return lessonId：课程有效，null：课程无效，不能学习
     */
    @Override
    public Long isLessonValid(Long courseId) {
        //1、根据课程id查到课程
        Long userId = UserContext.getUser();
        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningLesson::getCourseId, courseId).eq(LearningLesson::getUserId, userId);
        LearningLesson learningLesson = this.getOne(queryWrapper);

        //2、进行判断是否有该课程
        if (ObjectUtil.isEmpty(learningLesson)) {
            return null;
        }

        //3、判断是否过期,是否失效，或者过了有效时间
        if (learningLesson.getStatus() == 3 || learningLesson.getExpireTime().isBefore(LocalDateTime.now())) {
            return null;
        }

        return learningLesson.getId();
    }

    /**
     * 统计课程学习人数
     *
     * @param courseId 课程id
     * @return 学习人数
     */
    @Override
    public Integer countLearningLessonByCourse(Long courseId) {
        //1、构建查询条件
        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(LearningLesson::getCourseId, courseId)
                .in(LearningLesson::getStatus,
                        LessonStatus.NOT_BEGIN.getValue(),
                        LessonStatus.LEARNING.getValue(),
                        LessonStatus.FINISHED.getValue());

        //2、发起查询
        int count = count(queryWrapper);

        return count;
    }

    /**
     * 用户删除课程
     *
     * @param courseId 课程id
     */
    @Override
    public void deleteLesson(Long courseId) {
        Long userId = UserContext.getUser();
        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningLesson::getCourseId, courseId).eq(LearningLesson::getUserId, userId);

        this.remove(queryWrapper);
    }

    /**
     * 退款后删除课程
     *
     * @param userId    用户id
     * @param courseIds 课程id
     */
    @Override
    public void deleteMyLessonsByCourseIds(Long userId, List<Long> courseIds) {
        //1、删除课程,变量删除
        for (Long courseId : courseIds) {
            LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(LearningLesson::getCourseId, courseId).eq(LearningLesson::getUserId, userId);
            this.remove(queryWrapper);
        }
    }

    /**
     * 创建或者更新课表计划
     *
     * @param planDTO 课程表id和每周学习频率
     */
    @Override
    public void addLearningPlan(LearningPlanDTO planDTO) {
        //1、查询课表信息
        LearningLesson learningLesson = lambdaQuery()
                .eq(LearningLesson::getCourseId, planDTO.getCourseId())
                .eq(LearningLesson::getUserId, UserContext.getUser())
                .one();

        AssertUtils.isNotNull(learningLesson, "修改课表不存在");

        //2、更新课表信息计划信息
        boolean update = lambdaUpdate()
                .set(LearningLesson::getWeekFreq, planDTO.getFreq())
                .set(ObjectUtil.equals(learningLesson.getPlanStatus(), PlanStatus.NO_PLAN.getValue()), LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING.getValue())
                .eq(LearningLesson::getId, learningLesson.getId())
                .update();
        if (!update) {
            throw new DbException("更新计划失败");
        }

    }

    /**
     * 查询学习计划进度
     *
     * @param pageQuery 分页查询条件
     * @return 学习计划进度所需结果集
     */
    @Override
    public LearningPlanPageVO pageQueryLearningPlan(PageQuery pageQuery) {
        //1、分页查询当前用户有学习计划的课表课程
        //1.1、获取当前用户的id
        Long userId = UserContext.getUser();

        //1.2、查询当前用户所购买的课程
        Page<LearningLesson> learningLessonPage = new Page<>(pageQuery.getPageNo(), pageQuery.getPageSize());
        //1.2.1、默认按学习时间降序
        learningLessonPage.addOrder(new OrderItem("latest_learn_time", false));


        Page<LearningLesson> page = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus,PlanStatus.PLAN_RUNNING.getValue())
                .eq(LearningLesson::getStatus,LessonStatus.LEARNING.getValue())
                .page(learningLessonPage);

        List<LearningLesson> lessons = page.getRecords();

        //1.3、根据当前用户所购买的课程中的课程id来获得一些课程的基本信息
        Set<Long> courseIds = lessons.stream().map(LearningLesson::getCourseId).collect(Collectors.toSet());

        //1.3.1、查询用户课程的基本信息
        List<CourseSimpleInfoDTO> courseInfos = courseClient.getSimpleInfoList(courseIds);

        //1.3.2、将课程信息集合转化成map
        Map<Long, CourseSimpleInfoDTO> courseInfoMap = courseInfos.stream().collect(Collectors.toMap(CourseSimpleInfoDTO::getId, s -> s));

        //2、分别统计各个课程本周学习的小结数量
        LocalDateTime weekBeginTime = DateUtils.getWeekBeginTime(LocalDate.now());
        LocalDateTime weekEndTime = DateUtils.getWeekEndTime(LocalDate.now());

        //SELECT lesson_id id,COUNT(*) AS num FROM learning_record WHERE finished = 1 AND user_id = 2
        //AND finish_time BETWEEN '2024-08-18 00:00:00' AND '2024-08-25 23:59:59' GROUP BY lesson_id

        //构建查询
        QueryWrapper<LearningRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("lesson_id AS id,COUNT(*) AS num")
                .eq("finished",true)
                .eq("user_id",2L)
                .between("finish_time",weekBeginTime,weekEndTime)
                .groupBy("lesson_id");

        List<Map<String, Object>> maps = recordMapper.selectMaps(queryWrapper);

        //2.1、将maps集合转成Id与num作为键值对的map集合
        Map<Long, Long> counts = maps.stream().collect(Collectors.toMap(map -> (Long) map.get("id"), map ->(Long) map.get("num")));

        //3、开始封装结果集中的list部分
        List<LearningPlanVO> learningPlanVOS = new ArrayList<>(lessons.size());

        for (LearningLesson lesson : lessons) {
            CourseSimpleInfoDTO courseSimpleInfoDTO = courseInfoMap.get(lesson.getCourseId());
            LearningPlanVO learningPlanVO = BeanUtil.toBean(lesson, LearningPlanVO.class);
            learningPlanVO.setCourseName(courseSimpleInfoDTO.getName());
            learningPlanVO.setSections(courseSimpleInfoDTO.getSectionNum());
            learningPlanVO.setWeekLearnedSections(Math.toIntExact(counts.getOrDefault(lesson.getId(),0L)));
            learningPlanVOS.add(learningPlanVO);
        }

        //4、进行本周已学完小结统计
        Collection<Long> values = counts.values();
        long sum = values.stream().mapToLong(value -> value).sum();

        //5、进行本周要学的总小结统计
        List<LearningLesson> list = lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getPlanStatus, PlanStatus.PLAN_RUNNING.getValue())
                .eq(LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .list();

        int total = list.stream().mapToInt(LearningLesson::getWeekFreq).sum();


        //6、封装结果集
        LearningPlanPageVO learningPlanPageVO = new LearningPlanPageVO();
        learningPlanPageVO.setWeekTotalPlan(total);
        learningPlanPageVO.setWeekFinished(Math.toIntExact(sum));
        learningPlanPageVO.setWeekPoints(0);
        learningPlanPageVO.setList(learningPlanVOS);



        return learningPlanPageVO;
    }


}
